from django.db import models
from django.db.models import permalink
from django.contrib.auth.models import User
import datetime, re
from django.utils.html import escape


class ListDocManager(models.Manager):
    """
    Takes a request and returns the ListDoc for the user.
    
    (??? really not needed, but wanted to construct it this way
    to deal with more complexity in the future)
    """
    def get_user_list(self, request):
        user_list_doc = self.get(user=request.user.id)
        return user_list_doc


class ListDoc(models.Model):
    """
    This is the model for the task list that ties each one to only one user.
    When as list is saved it creates a formatted copy to improve performance
    over templatetags. It provides all list manipulation features.  No changes
    should be made to a list outside of a complete edit of the list or the
    functions incliuded
    
    """
    # It has been recommended not to use models.OnetoOne and instead use
    # ForeignKey with unique=True, so that was done to link to the User
    user = models.ForeignKey(User, unique=True, editable=False)
    created = models.DateTimeField(auto_now_add=True) # ??? auto maybe dangerous
    modified = models.DateTimeField(auto_now=True) # ??? auto maybe dangerous
    raw_content =  models.TextField("Task List") # the todo.txt
    content = models.TextField(blank=True, editable=False) # html format of todo.txt
    
    objects = ListDocManager() # Use the mananger
    
    def save(self):
        """When the list is saved we put formatted version of the Todo.txt info in
        self.content.  It replaces @contexts and p:projects with links to the views
        for those items.
        """
        # ??? Is there a smarter way to do both of these formattings?
        format_context = re.compile(r'@(\w+)')
        format_project = re.compile(r'p:(\w+)')
        # ??? Can we use a reverse() to grab the url instead of hardcoding?
        temp = format_project.sub(r"<a href='/onli/project/\1/'>p:\1</a>", escape(self.raw_content))
        self.content = format_context.sub(r"<a href='/onli/context/\1/'>@\1</a>", temp)
        super(ListDoc, self).save()
    
    @permalink
    def get_absolute_url(self):
        return ('list_all', ())
    
    class Admin:
        pass
    
    def __unicode__(self):
        return "%s" % self.user
        
    def get_enum_list(self, query='', raw=False ):
        """ Takes an optional query returns a dictionary where the keys
        are the line numbers from the raw_content field.  Using the 'raw' option
        you can request formatted or raw version of the list. It also returns the
        hash of the raw_content so you can verify any manipulations are performed
        against the correct line numbers.
        """
        query = query.lower() # all queries are made using lower case
        check_hash = hash(self.raw_content)
        if raw:
            all_items = self.raw_content.splitlines()
        else:
            all_items = self.content.splitlines()
        result_items = {}
        if not query:
            for index, item in enumerate(all_items):
                result_items[index] = item
        for index, item in enumerate(all_items):
            if item.lower().find(query) != -1:
                result_items[index] = item
        return check_hash, result_items
        
    def mark_item(self,item_num,check_hash):
        """ Marks items in the list complete using the format 'x YYYY-MM-DD'.
        It will not add a mark twice.
        """
        current_hash = hash(self.raw_content)
        if current_hash == int(check_hash):
            item_num = int(item_num)
            all_items = self.raw_content.splitlines()
            # Don't add mark if it is completed, i.e., starts with 'x '
            if all_items[item_num].split()[0] != 'x':
                all_items[item_num] = 'x '+datetime.date.today().strftime("%Y-%m-%d")+' '+ all_items[item_num]
                self.raw_content='\n'.join(all_items)
                self.save()
            else:
                return False
    
class UserProfile(models.Model):
    """
    Extends the user model to include new parameters used on the site.
    """
    mobile_email = models.EmailField()
    user = models.ForeignKey(User, unique=True, editable=False)
    
    class Admin:
        pass
    
    def __unicode__(self):
        return "%s" % self.user
